﻿namespace PrismEx.Modules.DialogService
{
    using System;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Controls;

    using Microsoft.Practices.Prism.Commands;
    using Microsoft.Practices.Prism.Regions;

    [Export(typeof(Dialog))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    [TemplatePart(Name = "PART_Content", Type = typeof(ContentControl))]
    [TemplatePart(Name = "PART_Commands", Type = typeof(ItemsControl))]
    public class Dialog : Window
    {
        private readonly IRegionManager regionManager;

        private const int GWL_STYLE = -16;
        private const int DISABLE_MINIMIZE = -131073;
        private const int DISABLE_MAXIMIZE = -65537;

        [DllImport("user32.dll")]
        internal extern static int SetWindowLong(IntPtr hwnd, int index, int value);

        [DllImport("user32.dll")]
        internal extern static int GetWindowLong(IntPtr hwnd, int index);

        public static readonly DependencyProperty ShowMaximizeButtonProperty =
            DependencyProperty.Register("IsMaximizeEnabled", typeof(bool), typeof(Dialog), new UIPropertyMetadata(true, (d, e) => UpdateMaxAndMinAvailability(d as Dialog)));

        public static readonly DependencyProperty ShowMinimizeButtonProperty =
            DependencyProperty.Register("IsMinimizeEnabled", typeof(bool), typeof(Dialog), new UIPropertyMetadata(true, (d, e) => UpdateMaxAndMinAvailability(d as Dialog)));

        private string regionName;

        static Dialog()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Dialog), new FrameworkPropertyMetadata(typeof(Dialog)));
        }

        [ImportingConstructor]
        public Dialog(IRegionManager regionManager)
        {
            this.regionManager = regionManager.CreateRegionManager();
            regionName = "region_" + Guid.NewGuid();
            this.Owner = Application.Current.MainWindow;
            this.WindowStartupLocation = WindowStartupLocation.CenterOwner;
        }


        public bool IsMaximizeEnabled
        {
            get { return (bool)GetValue(ShowMaximizeButtonProperty); }
            set { SetValue(ShowMaximizeButtonProperty, value); }
        }

        public bool IsMinimizeEnabled
        {
            get { return (bool)GetValue(ShowMinimizeButtonProperty); }
            set { SetValue(ShowMinimizeButtonProperty, value); }
        }

        private DependencyObject contentHost;
        private ItemsControl commandHost;

        private Uri uri;

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            contentHost = this.GetTemplateChild("PART_Content");
            commandHost = this.GetTemplateChild("PART_Commands") as ItemsControl;

            if (contentHost != null)
            {
                contentHost.SetValue(RegionManager.RegionManagerProperty, regionManager);
                contentHost.SetValue(RegionManager.RegionNameProperty, regionName);
                regionManager.Regions[regionName].ActiveViews.CollectionChanged += ActiveViewsCollectionChanged;
                regionManager.RequestNavigate(regionName, uri);
            }
        }



        public void ShowDialog(Uri uri)
        {
            this.uri = uri;
            this.ShowDialog();
        }

        private void ActiveViewsCollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.NewItems != null && e.NewItems.Count > 0)
            {
                var frameworkElement = e.NewItems[0] as FrameworkElement;

                if (frameworkElement == null) return;

                var dialogContent = frameworkElement as IDialogContent ?? frameworkElement.DataContext as IDialogContent;

                if (dialogContent != null)
                {
                    this.Title = dialogContent.Title;
                    this.commandHost.ItemsSource =
                        dialogContent.Commands
                        .OrderBy(c => c.Order)
                        .Select(
                            c => new
                                {
                                    Content = c.Content,
                                    Command = new DelegateCommand<object>(
                                     o =>
                                         {
                                             if (c.Command != null)
                                             {
                                                 c.Command.Execute(o);
                                             }

                                             if (c.IsDialogTerminator) this.Close();
                                         },
                                     o => c.Command == null || c.Command.CanExecute(o))
                                });
                }
            }
        }

        private static void UpdateMaxAndMinAvailability(Dialog dialog)
        {
            var hwnd = new System.Windows.Interop.WindowInteropHelper(dialog).Handle;
            long value = GetWindowLong(hwnd, GWL_STYLE);

            if (!dialog.IsMaximizeEnabled) value &= DISABLE_MAXIMIZE;
            if (!dialog.IsMinimizeEnabled) value &= DISABLE_MINIMIZE;

            SetWindowLong(hwnd, GWL_STYLE, (int)(value));
        }
    }
}